export default class Utils {
  static date(format, unix) { // 时间格式化工具
    unix = unix || Date.now()

    var date = unix

    if (date.toString().length < 11) { date *= 1000 }

    date = new Date(date)

    var matches = format.match(/[YyMmwDdHhIiSs]/g)

    var ctrl = this

    matches.forEach(function(item) {
      if (item == 'Y') { format = format.replace(/Y/, date.getFullYear()) } else if (item == 'y') { format = format.replace(/y/, date.getFullYear().toString().substring(2)) } else if (item == 'M') { format = format.replace(/M/, (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) } else if (item == 'm') { format = format.replace(/m/, date.getMonth() + 1) } else if (item == 'w') {
        var week = ''
        var weeks = new Array('星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六')
        week = weeks[date.getDay()]
        format = format.replace(/w/, week)
      } else if (item == 'D') { format = format.replace(/D/, date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) } else if (item == 'd') { format = format.replace(/d/, date.getDate()) } else if (item == 'H') {
        var hours = ''
        if (date.getHours() >= 10) { hours = date.getHours() } else { hours = '0' + date.getHours() }
        format = format.replace(/H/, hours)
      } else if (item == 'h') {
        var hours = ''
        if (date.getHours() >= 12) { hours = '下午' + (date.getHours() - 12) } else { hours = '上午' + date.getHours() }
        format = format.replace(/h/, hours)
      } else if (item == 'i') { format = format.replace(/i/, date.getMinutes()) } else if (item == 'I') {
        var minute = ''
        if (date.getMinutes() >= 10) { minute = date.getMinutes() } else { minute = '0' + date.getMinutes() }
        format = format.replace(/I/, minute)
      } else if (item == 's') { format = format.replace(/s/, date.getSeconds()) } else if (item == 'S') {
        var seconds = ''
        if (date.getSeconds() >= 10) { seconds = date.getSeconds() } else { seconds = '0' + date.getSeconds() }
        format = format.replace(/S/, seconds)
      }
    })

    return format
  }

  static unique(arr) { // 数组去重
    var res = arr.filter(function(item, index, array) {
      return array.indexOf(item) == index
    })

    return res
  }

  static objUnique(arr, name) { // 数组对象去重
    var obj = {}

    arr = arr.reduce(function(prev, cur, index, array) {
      obj[cur[name]] ? '' : (obj[cur[name]] = true && prev.push(cur))
      return prev
    }, [])

    return arr
  }

  static flat(arr) { // 数组扁平化
    var res = []
    var i = 0

    for (i; i < arr.length; i++) {
      if (Array.isArray(arr[i])) { res = res.concat(Utils.flat(arr[i])) } else { res.push(arr[i]) }
    }

    return res
  }

  static deepClone2(obj) { // 深拷贝
    let cloneObj

    if (['number', 'string', 'boolean', 'undefined', 'symbol'].includes(typeof obj) || obj == null) {
      cloneObj = obj
      return cloneObj
    }

    const constructor = obj.constructor || Object

    cloneObj = new constructor()

    Object.entries(obj).forEach(function([key, value]) {
      cloneObj[key] = Utils.deepClone2(value)
    })

    return cloneObj
  }

  static checkType(any) {
    return Object.prototype.toString.call(any).slice(8, -1)
  }

  static deepClone(obj) { // 深拷贝
    const type = Utils.checkType(obj)
    if (type === 'Object') {
      const temp = Object.create(Object.prototype)
      for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
          temp[key] = Utils.deepClone(obj[key])
        }
      }
      return temp
    } else if (type === 'Array') {
      const temp = []
      for (let i = 0; i < obj.length; i++) {
        temp[i] = Utils.deepClone(obj[i])
      }
      return temp
    } else if (type === 'Function') {
      return obj.bind(this)
    } else if (type === 'Date') {
      return obj
    } else if (type === 'RegExp') {
      return new RegExp(obj)
    } else if (type === 'Set') {
      const temp = new Set()
      for (const val of obj.values()) {
        temp.add(Utils.deepClone(val))
      }
      return temp
    } else if (type === 'Map') {
      const temp = new Map()
      obj.forEach((value, key) => {
        temp.set(key, Utils.deepClone(value))
      })
      return temp
    }
    return obj
  }

  static debounce(func, wait) { // 防抖函数
    var timeout

    return function() {
      var ctrl = this
      var args = arguments
      clearTimeout(timeout)

      timeout = setTimeout(function() {
        func.apply(ctrl, args)
      }, wait)
    }
  }

  static throttle(func, wait) { // 节流函数
    let context, args, prevArgs, argsChanged, result
    let previous = 0
    return function() {
      let now, remaining
      if (wait) {
        now = Date.now()
        remaining = wait - (now - previous)
      }
      context = this
      args = arguments
      argsChanged = JSON.stringify(args) != JSON.stringify(prevArgs)
      prevArgs = { ...args }
      if (argsChanged || wait && (remaining <= 0 || remaining > wait)) {
        if (wait) {
          previous = now
        }
        result = func.apply(context, args)
        context = args = null
      }
      return result
    }
  }

  static numfix(num) { // 数字转为w
    return num / 10000 >= 1
      ? (num / 10000).toFixed(2) + 'w'
      // : num / 1000 >= 1
      // ? (num / 1000).toFixed(2) + "k"
      : num
  }

  static timeSpace(prev, now, during) { // 时间间隔 显示时间(上一时间, 当前时间 , 间隔时间(分))
    if (!prev) { return true }

    if (parseInt(now) - parseInt(prev) > during * 60 * 1000) { return true }

    return false
  }

  static daySpace(time) { // 与今天相差时间， 今天， 昨天， 星期几
    const ptime = time
    const twentyFourHours = 24 * 60 * 60 * 1000
    const fortyEightHours = 24 * 60 * 60 * 1000 * 2
    const date = new Date()
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
    const today = `${year}-${month}-${day}`
    const todayTime = new Date(today).getTime()
    const yesterdayTime = new Date(todayTime - twentyFourHours).getTime()
    const lastYesterdayTime = new Date(todayTime - fortyEightHours).getTime()

    if (ptime >= todayTime) { return '今天 ' + this.date('H:I', time) } else if (ptime < todayTime && yesterdayTime <= ptime) { return '昨天 ' + this.date('H:I', time) } else if (ptime < yesterdayTime && lastYesterdayTime <= ptime) { return '前天 ' + this.date('H:I', time) } else if (this.inWeek(time)) { return this.date('w H:I', time) } else { return this.date('Y-m-d H:I', time) }
  }

  static inWeek(timestamp) { // 判断是否为本周
    const todaysDate = new Date()
    // 获取今天是周几
    const day = todaysDate.getDay()
    // 计算一周的最后一天
    const lastWeek = new Date(todaysDate.getTime() + (7 - (day || 7)) * 24 * 60 * 60 * 1000)
    lastWeek.setHours(23, 59, 59, 999)
    // 计算一周的第一天
    const firstWeek = new Date(todaysDate.getTime() - ((day || 7) - 1) * 24 * 60 * 60 * 1000)
    firstWeek.setHours(0, 0, 0, 0)
    return timestamp <= lastWeek.getTime() && timestamp >= firstWeek.getTime()
  }

  static goBottom(elem) { // 去底部
    elem.scrollTop = elem.scrollHeight
  }

  static goTop(elem) { // 去顶部
    elem.scrollTop = 0
  }

  static transTime(value) { // 音乐进度条
    if (!value) { return '00:00' }

    var time = ''
    var h = parseInt(value / 3600)
    value %= 3600
    var m = parseInt(value / 60)
    m = m < 10 ? '0' + m : m
    var s = parseInt(value % 60)
    s = s < 10 ? '0' + s : s
    time = m + ':' + s
    return time
  }

  static numberThree(n) { // 每隔三位添加逗号
    var b = parseInt(n).toString()
    var len = b.length
    if (len <= 3) { return b }
    var r = len % 3
    return r > 0 ? b.slice(0, r) + ',' + b.slice(r, len).match(/\d{3}/g).join(',') : b.slice(r, len).match(/\d{3}/g).join(',')
  }

  static hoursDate(n) { // 小时转时间格式
    if (n <= 9) {
      return '0' + n + ':00'
    } else {
      return n + ':00'
    }
  }

  static setDateTime(fnTime, type) { // 时间格式 +8h
    var x = fnTime // 取得时间
    var time = new Date(x)
    var timeNum = 8// 小时数
    time.setHours(time.getHours() + timeNum)
    if (type) { time = new Date(time.getTime() + 86399999) }
    return time
  }

  static getUrl(name) { // 获取路由
    var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
    var r = window.location.search.substr(1).match(reg)
    if (r != null) return decodeURI(r[2])
    return null
  }

  /**
  * 数据转换为树形（递归），示例：toTreeByRecursion(source, 'id', 'parentId', null, 'children')
  * @param {Array} source 数据
  * @param {String} idField 标识字段名称
  * @param {String} parentIdField 父标识字段名称
  * @param {Any} parentIdNoneValue 父级标识空值
  * @param {String} childrenField 子节点字段名称
  * @param {Object} treeOption tree树形配置
  */
  static toTreeByRecursion(
    source = [],
    idField = 'id',
    parentIdField = 'parentId',
    parentIdNoneValue = '',
    childrenField = 'children',
    treeOption = undefined
  ) {
    const treeOptions = {
      enable: false, // 是否开启转tree插件数据
      keyField: 'key', // 标识字段名称，默认为key
      valueField: 'value', // 值字段名称，默认为value
      titleField: 'title', // 标题字段名称，默认为title

      keyFieldBind: 'id', // 标识字段绑定字段名称，默认为id
      valueFieldBind: 'id', // 值字段名称绑定字段名称，默认为id
      titleFieldBind: 'name' // 标题字段名称绑定字段名称，默认为name
    }
    // 合并tree树形配置
    if (treeOption) {
      Object.assign(treeOptions, treeOption)
    }

    // 对源数据深度克隆
    const cloneData = JSON.parse(JSON.stringify(source))
    return cloneData.filter(parent => {
      // 返回每一项的子级数组
      const branchArr = cloneData.filter(child => parent[idField] === child[parentIdField])

      // 绑定tree树形配置
      if (treeOptions.enable) {
        branchArr.map(child => {
          child[treeOptions.keyField] = child[treeOptions.keyFieldBind]
          child[treeOptions.valueField] = child[treeOptions.valueFieldBind]
          child[treeOptions.titleField] = child[treeOptions.titleFieldBind]
          return child
        })
      }

      // 如果存在子级，则给父级添加一个children属性，并赋值，否则赋值为空数组
      if (branchArr.length > 0) {
        parent[childrenField] = branchArr
      } else {
        // parent[childrenField] = []
      }

      // 绑定tree树形配置
      if (treeOptions.enable) {
        parent[treeOptions.keyField] = parent[treeOptions.keyFieldBind]
        parent[treeOptions.valueField] = parent[treeOptions.valueFieldBind]
        parent[treeOptions.titleField] = parent[treeOptions.titleFieldBind]
      }

      return parent[parentIdField] === parentIdNoneValue // 返回第一层
    })
  }

  static toTree(node, id, pid) { // 遍历树
    node.forEach(function(it) {
      delete it.children
    })
    // 定义map/
    var map = {}
    // 这里可以重构数据类型，放回字段值
    node.forEach(function(it) {
      map[it[id]] = it
    })

    // 定义返回集合
    var val = []
    node.forEach(function(it) {
      var parent = map[it[pid]]
      if (parent) {
        // 有数据说明不是顶级节点，将数据放到该 children 子节点下
        ((parent.children) || (parent.children = [])).push(it)
      } else {
        // 没有数据说明是顶级节点放到val中
        val.push(it)
      }
    })
    return val
  }

  static diffObject(newData, oldData) { // 对象差异化
    const newParams = {}

    Object.keys(newData).forEach(item => {
      if (oldData[item] != newData[item]) { newParams[item] = newData[item] }
    })

    return newParams
  }

  static phone(data) { // 隐藏手机号
    const text = data
    if (data) { return text.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }
    return text
  }

  static numfix(num) { // 数字转为w
    return num / 10000 >= 1
      ? (num / 10000).toFixed(2) + 'w'
      // : num / 1000 >= 1
      // ? (num / 1000).toFixed(2) + "k"
      : num
  }

  static timeSpace(prev, now, during) { // 时间间隔 显示时间(上一时间, 当前时间 , 间隔时间(分))
    if (!prev) { return true }

    if (parseInt(now) - parseInt(prev) > during * 60 * 1000) { return true }

    return false
  }

  static daySpace(time) { // 与今天相差时间， 今天， 昨天， 星期几
    const ptime = time
    const twentyFourHours = 24 * 60 * 60 * 1000
    const fortyEightHours = 24 * 60 * 60 * 1000 * 2
    const date = new Date()
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
    const today = `${year}-${month}-${day}`
    const todayTime = new Date(today).getTime()
    const yesterdayTime = new Date(todayTime - twentyFourHours).getTime()
    const lastYesterdayTime = new Date(todayTime - fortyEightHours).getTime()

    if (ptime >= todayTime) { return '今天 ' + this.date('H:I', time) } else if (ptime < todayTime && yesterdayTime <= ptime) { return '昨天 ' + this.date('H:I', time) } else if (ptime < yesterdayTime && lastYesterdayTime <= ptime) { return '前天 ' + this.date('H:I', time) } else if (this.inWeek(time)) { return this.date('w H:I', time) } else { return this.date('Y-m-d H:I', time) }
  }

  static inWeek(timestamp) { // 判断是否为本周
    const todaysDate = new Date()
    // 获取今天是周几
    const day = todaysDate.getDay()
    // 计算一周的最后一天
    const lastWeek = new Date(todaysDate.getTime() + (7 - (day || 7)) * 24 * 60 * 60 * 1000)
    lastWeek.setHours(23, 59, 59, 999)
    // 计算一周的第一天
    const firstWeek = new Date(todaysDate.getTime() - ((day || 7) - 1) * 24 * 60 * 60 * 1000)
    firstWeek.setHours(0, 0, 0, 0)
    return timestamp <= lastWeek.getTime() && timestamp >= firstWeek.getTime()
  }

  static goBottom(elem) { // 去底部
    elem.scrollTop = elem.scrollHeight
  }

  static goTop(elem) { // 去顶部
    elem.scrollTop = 0
  }

  static transTime(value) { // 音乐进度条
    if (!value) { return '00:00' }

    var time = ''
    var h = parseInt(value / 3600)
    value %= 3600
    var m = parseInt(value / 60)
    m = m < 10 ? '0' + m : m
    var s = parseInt(value % 60)
    s = s < 10 ? '0' + s : s
    time = m + ':' + s
    return time
  }

  static numberThree(n) { // 每隔三位添加逗号
    var b = parseInt(n).toString()
    var len = b.length
    if (len <= 3) { return b }
    var r = len % 3
    return r > 0 ? b.slice(0, r) + ',' + b.slice(r, len).match(/\d{3}/g).join(',') : b.slice(r, len).match(/\d{3}/g).join(',')
  }

  static hoursDate(n) { // 小时转时间格式
    if (n <= 9) {
      return '0' + n + ':00'
    } else {
      return n + ':00'
    }
  }

  static setDateTime(fnTime, type) { // 时间格式 +8h
    var x = fnTime // 取得时间
    var time = new Date(x)
    var timeNum = 8// 小时数
    time.setHours(time.getHours() + timeNum)
    if (type) { time = new Date(time.getTime() + 86399999) }
    return time
  }
}

